package com.dbms.execution.execution;

import com.dbms.common.Schema;
import com.dbms.common.Tuple;
import com.dbms.execution.plan.PlanNode;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * BackupExecutor (备份执行器) 负责执行数据库文件的备份计划。
 * 它通过将源数据库文件复制到指定的目标路径来工作。
 */
public class BackupExecutor implements Executor {

    /**
     * 源数据库文件的路径。
     */
    private final String sourceDbFile;

    /**
     * 备份文件要保存的目标路径。
     */
    private final String destinationPath;

    /**
     * 一个标志，用于确保备份操作只执行一次。
     */
    private boolean hasExecuted = false;

    /**
     * 构造函数，初始化备份执行器。
     * @param sourceDbFile 源数据库文件的路径
     * @param destinationPath 备份文件的目标路径
     */
    public BackupExecutor(String sourceDbFile, String destinationPath) {
        this.sourceDbFile = sourceDbFile;
        this.destinationPath = destinationPath;
    }

    /**
     * 打开执行器，准备执行。
     * 在这里，我们将执行状态重置为 false。
     */
    @Override
    public void open() {
        hasExecuted = false;
    }

    /**
     * 执行备份逻辑。
     * 这个方法只会在第一次调用时执行实际的备份操作。后续调用将返回 null。
     * 像备份这样的工具类操作不返回元组。
     * @return 总是返回 null。
     */
    @Override
    public Tuple next() {
        // 如果已经执行过，直接返回 null
        if (hasExecuted) {
            return null;
        }

        try {
            System.out.println("Starting backup from '" + sourceDbFile + "' to '" + destinationPath + "'...");
            // 使用 Java NIO Files.copy 方法来复制文件
            // Paths.get() 将字符串路径转换为 Path 对象
            // StandardCopyOption.REPLACE_EXISTING 表示如果目标文件已存在，则覆盖它
            Files.copy(Paths.get(sourceDbFile), Paths.get(destinationPath), StandardCopyOption.REPLACE_EXISTING);
            System.out.println("Backup completed successfully.");

        } catch (IOException e) {
            // 如果在复制过程中发生 IO 异常，抛出运行时异常并附带原始异常信息
            throw new RuntimeException("Backup failed: " + e.getMessage(), e);
        } finally {
            // 无论成功还是失败，都将 hasExecuted 标记为 true，以防止重复执行
            hasExecuted = true;
        }

        // DDL 或工具类操作不返回元组，所以返回 null
        return null;
    }

    /**
     * 关闭执行器。
     * 对于备份操作，不需要特殊的清理工作。
     */
    @Override
    public void close() { }

    /**
     * 获取输出模式。
     * 备份操作不产生任何输出元组，因此没有输出模式。
     * @return 总是返回 null。
     */
    @Override
    public Schema getSchema() {
        return null; // 无输出 Schema
    }

    /**
     * 获取关联的计划节点。
     * @return 总是返回 null。
     */
    @Override
    public PlanNode getPlanNode() {
        return null;
    }
}